package cn.edu.nju.ws.sview.crawler;

import java.io.BufferedInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;

import org.apache.log4j.Logger;

import cn.edu.nju.ws.sview.rdf.ResourceFactory;
import cn.edu.nju.ws.sview.rdf.URIResource;
import cn.edu.nju.ws.sview.util.LogUtil;

import com.hp.hpl.jena.ontology.OntModel;

/**
 * 爬虫下载文档类，并完成文档的解析和索引工作
 * @author Gong Saisai
 *
 */
public class Fetch {
	static Logger logger = LogUtil.getLogger(Fetch.class.getName()) ;
    private String uri =null ;
	private URLConnection conn = null;
    private CrawlerMeta meta;
    public Fetch(String uri,CrawlerMeta meta){
    	this.uri = uri;
    	this.meta = meta;
    }
    
    public static boolean isAcceptableURI(String uri){
    	if(uri==null) {
    		return false;
    	}
    	if(uri.length()<(new String("http://")).length()){
    		return false;
    	}
    	if(!uri.substring(0,(new String("http://")).length()).toLowerCase().equals("http://")){
    		return false;
    	}
    	return true;
    }
    
    public static String removeFragment(String uri){
    	if(uri==null) 
    		return null;
    	else{
    		int pos = uri.indexOf("#") ;
    		if(pos!=-1){
    			return uri.substring(0,pos) ;
    		}else
    			return uri;
    		
    	}
    	
    }
    
    /**
     * 关闭Fetech
     */
    public void close(){
        this.conn = null;
    }
    
    /**
     * 根据HTTP get协议，设置接受的contentType去dereference uri，
     *    获得可能的RDF文档(只是content type符合要求，还要看里面内容)
     * 需要处理3XX跳转情况
     * @return RDF文档 ，可能为NULL
     */
    public URIResource getDereferencDocument(){
    	URIResource dereferenceDoc = null;
    	int redirectNum = 0;
    	String currURIStr = this.uri;
    	outer: while(true){
    		if(redirectNum>this.meta.getMax_redirection_num()){
    			dereferenceDoc=null;
    			break outer;
    		}
    			
    		URL currURL = null;
			try {
				if (!isAcceptableURI(currURIStr))
					throw new MalformedURLException();
				currURL = new URL(currURIStr);
				String host = currURL.getHost();
				if(host==null || host.equals(""))
					throw new MalformedURLException();
			} catch (MalformedURLException e) {
				dereferenceDoc = null;
				break outer;
			}
			try {
				//必须要加上，不然所有的响应code均为200
				HttpURLConnection.setFollowRedirects(false);
				conn = currURL.openConnection();
				conn.setRequestProperty("User-Agent",this.meta.getUser_agent_request()) ;
			    conn.setConnectTimeout(this.meta.getConnect_timeout()) ;
			    conn.setReadTimeout(this.meta.getRead_timeout()) ;
			    conn.setRequestProperty("Accept", "application/rdf+xml; q=1, application/xhtml+xml; q=0.8, application/xml; q=0.4, text/xml; q=0.3");
			    conn.connect();
			    
			    if(conn instanceof HttpURLConnection){
			    	HttpURLConnection httpConn = (HttpURLConnection)conn;
			    	int code = httpConn.getResponseCode()/100;
			    	switch(code){
			    	case 2:{
			    		System.out.println("ping success");
			    		dereferenceDoc = ResourceFactory.getInstance().createURIResource(currURIStr) ;
			    		break outer;
			    	}
			    	case 3:{
			    		currURIStr = httpConn.getHeaderField("Location");
			    		if(currURIStr!=null)
			    		currURIStr =removeFragment(currURIStr.trim());
			    		break;
			    	}
			    	default:{
			    		dereferenceDoc = null;
			    		break outer;
			    	}
			    	}
			    }else{
			    	dereferenceDoc = null;
					break outer;
			    }
			    redirectNum++;
			} catch (IOException e) {
				// TODO Auto-generated catch block
				dereferenceDoc = null;
				break outer;
			}
    	}
    	return dereferenceDoc;
    }
    
    /**
     * 查看RDF文档内容是否符合要求，如果不符合则返回NULL
     * @param documet RDF文档
     * @return OntModel 不符合时返回NULL
     */
    public OntModel checkContent(URIResource document) {
		OntModel model = null;
    	if(document==null)
    		throw new IllegalArgumentException("参数不能为空");
    	String serializationFormat = null;
    	HttpURLConnection httpConn = null;
    	if(this.conn instanceof HttpURLConnection)
    		httpConn = (HttpURLConnection)this.conn;
    	String contentType = httpConn.getHeaderField("Content-Type") ;
    	if(contentType!=null){
    		String mediaType =null;
    		int colonPos = contentType.indexOf(";") ;
    		if(colonPos!=-1){
    			mediaType = contentType.substring(0,colonPos).trim().toLowerCase();
    		}else{
    			mediaType = contentType.trim().toLowerCase();
    		}
    		if(mediaType.equals("application/rdf+xml")){
    			serializationFormat = "RDF/XML" ;
    		}else if(mediaType.equals("application/xhtml+xml")){
    			serializationFormat = "RDFa";
    		}else if(mediaType.equals("application/xml")){
    			serializationFormat = "RDF/XML" ;
    		}else if(mediaType.equals("text/xml")){
    			serializationFormat = "RDF/XML" ;
    		}
    	}
    	if(serializationFormat!=null){
			ByteArrayOutputStream array = new ByteArrayOutputStream();
			BufferedInputStream in = null;
			try {
				in = new BufferedInputStream(httpConn.getInputStream());
				while (true) {
					int c = in.read();
					if (c != -1) {
						array.write(c);
					} else {
						break;
					}
				}
				
			} catch (IOException e) {
				// TODO Auto-generated catch block
				array = null;
			}finally{
				try {
					in.close();
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
			
			byte[] content = null;
			if(array!=null){
				content = array.toByteArray();
			}
			if(content!=null){
				try{
					model = Parser.getInstance().parse(document.getURI(), serializationFormat, content) ;
				}catch(Exception e){
					e.printStackTrace();
				}
			}
	      }
    	System.out.println("model is null? "+(model==null));
    	return model;
    }
}
